home *** CD-ROM | disk | FTP | other *** search
/ ADA Programming Guide / ADA Programming Guide.iso / ada_gwu / misc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-01-30  |  17.1 KB  |  792 lines

  1. /*
  2.  * Copyright (C) 1985-1992  New York University
  3.  * 
  4.  * This file is part of the Ada/Ed-C system.  See the Ada/Ed README file for
  5.  * warranty (none) and distribution info and also the GNU General Public
  6.  * License for more details.
  7.  
  8.  */
  9. /* misc.c - miscellaneous programs */
  10.  
  11.  
  12. #include "config.h"
  13. #include <stdlib.h>
  14. #include <stdio.h>
  15. #include <string.h>
  16. #include "time.h"
  17. #include "ifile.h"
  18. #include "miscp.h"
  19. #ifdef BSD
  20. #include <strings.h>
  21. #endif
  22.  
  23. #ifndef LIBDIR
  24. #define LIBDIR "/usr/local/lib"
  25. #endif
  26.  
  27. #ifdef ADALIB
  28. #define EXIT_INTERNAL_ERROR
  29. #endif
  30.  
  31. #ifdef BINDER
  32. #define EXIT_INTERNAL_ERROR
  33. extern int adacomp_option;
  34. #endif
  35.  
  36. #ifdef INT
  37. #define EXIT_INTERNAL_ERROR
  38. #endif
  39.  
  40. #ifndef EXPORT
  41. #undef EXIT_INTERNAL_ERROR
  42. #endif
  43. #ifdef BSD
  44. #include <sys/file.h>
  45. #endif
  46.  
  47. char *LIBRARY_PREFIX= "";
  48.  
  49. /* PREDEFNAME gives directory path to predef files.
  50.  * libset() is used to toggle between libraries (the users and predef).
  51.  * tname = libset(lname) sets library prefix for ifopen, etc. to lname
  52.  * and returns prior setting in tname.
  53.  */
  54.  
  55. static void openerr(char *filename, char *mode);
  56.  
  57. #ifdef SMALLOC
  58. unsigned int smalloc_free = 0;
  59. char    *smalloc_ptr;
  60. #define SMALLOC_BLOCK 2000
  61. char **smalloc_table = (char **)0;
  62. unsigned smalloc_blocks = 0;
  63. #endif
  64.  
  65. char *smalloc(unsigned n)                                        /*;smalloc*/
  66. {
  67.     /* variant of malloc for use for blocks that will never be freed,
  68.      * primarily blocks used for small strings. This permits allocation
  69.      * in larger blocks avoiding the malloc overhead required for each block.
  70.      */
  71. #ifndef SMALLOC
  72.     return emalloct(n, "smalloc");
  73. #else
  74.     char *p;
  75.     if (n & 1) n+= 1;
  76. #ifdef ALIGN4
  77.     if (n & 2) n+= 2;
  78. #endif
  79.  
  80.     if (n > SMALLOC_BLOCK) { /* large block allocated separately */
  81. #ifdef DEBUG
  82.         printf("smalloc: warning block %u exceeds %d SMALLOC_BLOCK\n",
  83.           n, SMALLOC_BLOCK);
  84. #endif
  85.         p = emalloct(n, "smalloc");
  86.         return p;
  87.     }
  88.     if (n > smalloc_free) {
  89.         smalloc_ptr = emalloct(SMALLOC_BLOCK, "smalloc-block");
  90.         smalloc_free = SMALLOC_BLOCK;
  91.         smalloc_blocks++;
  92.         if (smalloc_blocks == 1) {
  93.             smalloc_table = (char **) emalloct(sizeof (char **),
  94.               "smalloc-table");
  95.         }
  96.         else { /* reallocate blocks */
  97.             smalloc_table = (char **) erealloct((char *)smalloc_table,
  98.               sizeof(char **) * (smalloc_blocks), "smalloc-table-realloc");
  99.         }
  100.         smalloc_table[smalloc_blocks-1] = smalloc_ptr;
  101.     }
  102.     p = smalloc_ptr;
  103.     smalloc_ptr += n;
  104.     smalloc_free -= n;
  105.     return p;
  106. #endif
  107. }
  108.  
  109. #ifdef DEBUG
  110. void smalloc_list()
  111. {
  112.     int i;
  113.     char **st;
  114.     st = smalloc_table;
  115.     for (i = 0; i < smalloc_blocks; i++) {
  116.         printf("%d %ld %x\n", i, *st, *st);
  117.         st++;
  118.     }
  119. }
  120. #endif
  121.  
  122. int is_smalloc_block(char *p)                            /*;is_smalloc_block*/
  123. {
  124.     /* returns TRUE is p points within block allocated by smalloc */
  125. #ifdef SMALLOC
  126.     int i;
  127.     char **st;
  128.  
  129.     st = smalloc_table;
  130.     if (smalloc_blocks == 0) chaos("is_malloc_block - no blocks");
  131.     for (i = 0; i < smalloc_blocks; i++) {
  132.         if (*st <= p && p  < (*st+(SMALLOC_BLOCK-1)))
  133.             return TRUE;
  134.         st++;
  135.     }
  136.     return FALSE;
  137. #else
  138.     return FALSE;
  139. #endif
  140. }
  141.  
  142. void capacity(char *s)                /*;capacity*/
  143. {
  144.     /* called  when compiler capacity limit exceeded.
  145.      * EXIT_INTERNAL_ERROR is defined when the module is run by itself
  146.      * (not spawned from adacomp) and DEBUG is not defined.
  147.      */
  148. #ifdef EXIT_INTERNAL_ERROR
  149.     fprintf(stderr, "capacity limit exceeded: %s\n", s);
  150.     exitp(RC_INTERNAL_ERROR);
  151. #else
  152. #ifdef DEBUG
  153.     printf("capacity limit exceeded: %s\nexecution abandoned \n", s);
  154. #endif
  155.     fprintf(stderr, "capacity limit exceeded: %s\n", s);
  156.     exitp(RC_INTERNAL_ERROR);
  157. #endif
  158. }
  159.  
  160. #ifdef CHAOS
  161. void chaos(char *s)                                                /*;chaos*/
  162. {
  163.     /* called when internal logic error detected and it is not meaningful
  164.      * to continue execution. This is never defined for the export version.
  165.      */
  166.     fprintf(stderr, "chaos: %s\nexecution abandoned \n", s);
  167.     printf("chaos: %s\nexecution abandoned \n", s);
  168.     exitp(RC_INTERNAL_ERROR);
  169. }
  170. #else
  171. void exit_internal_error()                        /*;exit_internal_error*/
  172. {
  173.     /* called when internal logic error detected and it is not meaningful
  174.      * to continue execution. This procedure is called by the export version.
  175.      * EXIT_INTERNAL_ERROR is defined when the module is run by itself
  176.      * (not spawned from adacomp) and EXPORT is defined.
  177.      * Now that adabind is a separate module which can be called by itself
  178.      * or spawned from adacomp, we must test the run time flag adacomp_option
  179.      * to determine which case it is.
  180.      */
  181. #ifdef EXIT_INTERNAL_ERROR
  182. #ifdef BINDER
  183.     if (adacomp_option)
  184. #endif
  185.         fprintf(stderr, "Adaed internal error - Please report.\n");
  186.     exit(RC_INTERNAL_ERROR);
  187. #else
  188.     exit(RC_INTERNAL_ERROR);
  189. #endif
  190. }
  191. #endif
  192.  
  193. void exitp(int n)                                                /*;exitp*/
  194. {
  195.     /* synonym for exit() used so can trap exit() calls with debugger */
  196.     exit(n);
  197. }
  198.  
  199. char *ecalloc(unsigned nelem, unsigned nsize)            /*;ecalloc */
  200. {
  201.     /* calloc with error check if no more */
  202.  
  203.     char   *p;
  204.  
  205.     if (nelem > 20000) chaos("ecalloc: ridiculous argument");
  206.  
  207.     p = calloc (nelem, nsize);
  208.     if (p == (char *) 0)
  209.         capacity("out of memory \n");
  210.     return p;
  211. }
  212.  
  213. char *emalloc(unsigned n)                                        /*;emalloc */
  214. {    /* avoid BUGS - use calloc which presets result to zero  ds 3 dec 84*/
  215.     /* malloc with error check if no more */
  216.  
  217.     char   *p;
  218.  
  219.     if (n > 50000) chaos("emalloc: ridiculous argument");
  220.     p = calloc (1, n);
  221.     if (p == (char *) 0)
  222.         capacity("out of memory \n");
  223.     return (p);
  224. }
  225.  
  226. char *erealloc(char *ptr, unsigned size)                        /*;eralloc */
  227. {
  228.     /* realloc with error check if no more */
  229.  
  230.     char   *p;
  231.  
  232.     p = realloc (ptr, size);
  233.     if (p == (char *) 0)
  234.         capacity("erealloc: out of memory \n");
  235.     return (p);
  236. }
  237.  
  238. char *strjoin(char *s1, char *s2)                                /*;strjoin */
  239. {
  240.     /* return string obtained by concatenating argument strings
  241.      * watch for either argument being (char *)0 and treat this as null string
  242.      */
  243.  
  244.     char   *s;
  245.  
  246.     if (s1 == (char *)0) s1= "";
  247.     if (s2 == (char *)0) s2 = "";
  248.     s = smalloc((unsigned) strlen(s1) + strlen(s2) + 1);
  249.     strcpy(s, s1);
  250.     strcat(s, s2);
  251.     return s;
  252. }
  253.  
  254. int streq(char *a, char *b)                                            /*;streq*/
  255. {
  256.     /* test two strings for equality, allowing for null pointers */
  257.     if (a == (char *)0 && b == (char *)0)
  258.         return TRUE;
  259.     else if (a == (char *)0 || b == (char *)0)
  260.         return FALSE;
  261.     else return (strcmp(a, b) == 0);
  262. }
  263.  
  264. char *substr(char *s, int i, int j)                                /*;substr */
  265. {
  266.     /* return substring s(i..j) if defined, else return null ptr*/
  267.  
  268.     int    n;
  269.     char    *ts, *t;
  270.  
  271.     if (s == (char *)0) return (char *) 0;
  272.     n = strlen(s);
  273.     if (!(i > 0 && j <= n && i <= j)) return (char *)0;
  274.     /* allocate result, including null byte at end */
  275.     ts = smalloc((unsigned) j - i + 2);
  276.     t = ts;
  277.     s = s + (i - 1); /* point to start of source*/
  278.     for (; i <= j; i++) *t++ = *s++; /* copy characters */
  279.     *t = '\0'; /* terminate result */
  280.     return ts;
  281. }
  282.  
  283. /* getopt(3) procedure obtained from usenet */
  284. /*
  285.  * getopt - get option letter from argv
  286.  */
  287. #ifdef IBM_PC
  288. #define nogetopt
  289. #endif
  290.  
  291. #ifdef nogetopt
  292. char   *optarg;                /* Global argument pointer. */
  293. int    optind = 0;                /* Global argv index. */
  294.  
  295. static char *scan = NULL;    /* Private scan pointer. */
  296.  
  297. int getopt(int argc, char **argv, char *optstring)                /*;getopt */
  298. {
  299.     register char   c;
  300.     register char  *place;
  301.     optarg = NULL;
  302.  
  303.     if (scan == NULL || *scan == '\0') {
  304.         if (optind == 0)
  305.             optind++;
  306.  
  307.         if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0')
  308.             return (EOF);
  309.         if (strcmp (argv[optind], "--") == 0) {
  310.             optind++;
  311.             return (EOF);
  312.         }
  313.  
  314.         scan = argv[optind] + 1;
  315.         optind++;
  316.     }
  317.  
  318.     c = *scan++;
  319.     place = strchr (optstring, c);
  320.  
  321.     if (place == NULL || c == ':') {
  322.         fprintf (stderr, "%s: unknown option -%c\n", argv[0], c);
  323.         return ('?');
  324.     }
  325.  
  326.     place++;
  327.     if (*place == ':') {
  328.         if (*scan != '\0') {
  329.             optarg = scan;
  330.             scan = NULL;
  331.         }
  332.         else {
  333.             optarg = argv[optind];
  334.             optind++;
  335.         }
  336.     }
  337.     return (c);
  338. }
  339. #endif
  340.  
  341. char *greentime(int un)                                        /*;greentime*/
  342. {
  343.     /* get greenwich time in string of 23 characters.
  344.      * format of result is as follows
  345.      *    1984 10 02 16 30 36 nnn
  346.      *    123456789a123456789b123
  347.      *    year mo da hr mi se uni
  348.      *
  349.      * greenwich time is used to avoid problems with daylight savings time.
  350.      * The last three characters are the compilation unit number
  351.      * (left filled with zeros if necessary).
  352.      * NOTE: changed to use local time to give approx. same time as
  353.      * SETL version            ds  20 nov 84
  354.      */
  355.  
  356.     char    *s;
  357. #ifndef IBM_PC
  358.     long clock;
  359. #else
  360.     /* IBM_PC (Metaware) */
  361.     time_t clock;
  362. #endif
  363.     /*struct tm *gmtime();*/
  364.     struct tm *t;
  365. #ifndef IBM_PC
  366.     clock = time(0);
  367. #else
  368.     time(&clock);
  369. #endif
  370.     s = smalloc(24);
  371.     /*t = gmtime(&clock);*/
  372.     t = localtime(&clock);
  373.     sprintf(s,"%04d %02d %02d %02d %02d %02d %03d",
  374. #ifdef IBM_PC
  375.       /* needed until Metaware fixes bug in tm_year field (ds 6-19-86) */
  376.       t->tm_year , t->tm_mon + 1, t->tm_mday,
  377. #else
  378.       t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
  379. #endif
  380.       t->tm_hour, t->tm_min, t->tm_sec, un);
  381.     return s;
  382. }
  383.  
  384. FILE *efopenl(char *filename, char *suffix, char *type, char *mode)    /*;efopenl*/
  385. {
  386.     char       *fname;
  387.     FILE       *f;
  388.  
  389.     fname = ifname(filename, suffix);
  390.     f =  efopen(fname, type, mode);
  391.     efree(fname);
  392.     return f;
  393. }
  394.  
  395. FILE *efopen(char *filename, char *type, char *mode)                /*;efopen*/
  396. {
  397.     FILE    *f;
  398. #ifdef IBM_PC
  399.     char    *p;
  400.     /* mode only meaningful for IBM PC for now */
  401.  
  402.     p = emalloc((unsigned) (strlen(type) + strlen(mode) + 1));
  403.     strcpy(p, type);
  404.     strcat(p, mode);
  405.     f = fopen(filename, p);
  406.     efree(p);
  407. #else
  408.     f = fopen(filename, type);
  409. #endif
  410.     if (f == (FILE *)0)
  411.         openerr(filename, type);
  412.     return f;
  413. }
  414.  
  415. void efree(char *p)                                                /*;efree*/
  416. {
  417.     /* free with check that not tryig to free null pointer*/
  418.     if (p == (char *)0)
  419.         chaos("efree: trying to free null pointer");
  420.     free(p);
  421. }
  422.  
  423. int strhash(char *s)                                        /*;strhash*/
  424. {
  425.     /* Hashing function from strings to numbers */
  426.  
  427.     register int hash = 0;
  428.  
  429.     /* add character values together, adding in the cumulative hash code
  430.      * at each step so that 'ABC' and 'BCA' have different hash codes.
  431.      */
  432.     while (*s)
  433.         hash += hash + *s++;
  434.     if (hash < 0) hash = - hash; /* to avoid negative hash code */
  435.     return hash;
  436. }
  437.  
  438. char *unit_name_type(char *u)                            /*;unit_name_type*/
  439. {
  440.     int    n;
  441.     char    *s;
  442.  
  443.     n = strlen(u);
  444.     if (n < 2) {
  445.         s = smalloc(1); 
  446.         *s = '\0'; 
  447.         return s;
  448.     }
  449.     /* otherwise, return first two characters */
  450.     s = smalloc(3);
  451.     s[0] = u[0];
  452.     s[1] = u[1];
  453.     s[2] = '\0';
  454.     return s;
  455. }
  456.  
  457. #ifdef BSD
  458. /* BSD doesn't support strchr() and strrchr(), but they are just
  459.  * named index() and rindex(), respectively, so here is code for BSD
  460.  */
  461. char *strchr(const char *s, int c)
  462. {
  463.     return index(s, (char) c);
  464. }
  465.  
  466. char *strrchr(const char *s, int c)
  467. {
  468.     return rindex(s, (char) c);
  469. }
  470. #endif
  471.  
  472. char *libset(char *lname)                                        /*;libset*/
  473. {
  474.     char *old_name;
  475.  
  476.     old_name = LIBRARY_PREFIX;
  477.     LIBRARY_PREFIX = lname;
  478.     return old_name;
  479. }
  480.  
  481. char *ifname(char *filename, char *suffix)                        /*;ifname*/
  482. {
  483.     char *fname;
  484.  
  485.     /* allow room for library prefix, file name and suffix */
  486.     fname = emalloc((unsigned) (strlen(LIBRARY_PREFIX) + strlen(filename) +
  487.       strlen(suffix) + 3));
  488.     if (strlen(LIBRARY_PREFIX)) { /* prepend library prefix if present */
  489.         strcpy(fname, LIBRARY_PREFIX);
  490. #ifdef IBM_PC
  491.         strcat(fname, "\\");
  492. #endif
  493. #ifdef BSD
  494.         strcat(fname, "/");
  495. #endif
  496. #ifdef SYSTEM_V
  497.         strcat(fname, "/");
  498. #endif
  499.         strcat(fname, filename);
  500.     }
  501.     else {
  502.         strcpy(fname, filename); /* copy name if no prefix */
  503.     }
  504.     if (strlen(suffix)) {
  505.         strcat(fname, ".");
  506.         strcat(fname, suffix);
  507.     }
  508.     return fname;
  509. }
  510.  
  511. IFILE *ifopen(char *filename, char *suffix, char *mode, int pass)    /*;ifopen*/
  512. {
  513.     FILE  *file;
  514.     char  modec;
  515.     char  *fname;
  516.     long  s = 0L;
  517.     int   nr, opened = FALSE, error = FALSE;
  518.     IFILE  *ifile;
  519. #ifdef IBM_PC
  520.     char *t_name;
  521. #endif
  522.  
  523.     modec= mode[0];
  524.  
  525.     fname = ifname(filename, suffix); /* expand file name */
  526.  
  527. #ifdef IBM_PC
  528.     /* mode only meaningful for IBM PC for now */
  529.     t_name = emalloc((unsigned) (strlen(mode) + 2));
  530.     strcpy(t_name, mode);
  531.     strcat(t_name, "b");
  532.     file = fopen(fname, t_name);
  533.     efree(t_name);
  534. #else
  535.     file = fopen(fname, mode);
  536. #endif
  537.  
  538.     if (file == (FILE *)0) {
  539.         if (pass)
  540.             return (IFILE *) 0;
  541.         else
  542.             openerr(fname, mode);
  543.     }
  544.     ifile = (IFILE *) emalloc(sizeof(IFILE));
  545.     if (modec == 'w') { /* write header */
  546.         /* write long at start to later be replaced with slots offset */
  547.         ifile->fh_mode = modec;
  548.         ifile->fh_slots = 0;
  549.         ifile->fh_units_end = 0;
  550.         /* will be upated on close */
  551.         fwrite((char *) ifile, sizeof(IFILE), 1, file);
  552.     }
  553.     else if (modec == 'r') { /* read and check header */
  554.         nr = fread((char *) ifile, sizeof(IFILE), 1, file);
  555.  
  556.         if (nr != 1) {
  557. #ifdef DEBUG
  558.             printf("ifopen - unable to read header\n");
  559. #endif
  560.             error = TRUE;
  561.         }
  562.     }
  563.     if (error) {
  564.         openerr(fname, mode);
  565.     }
  566.     ifile->fh_file = file;
  567.     ifile->fh_mode = modec;
  568.  
  569.     efree(fname);
  570.     return ifile;
  571. }
  572.  
  573. static void openerr(char *filename, char *mode)                    /*;openerr*/
  574. {
  575.     /* EXIT_INTERNAL_ERROR is defined when the module is run by itself
  576.      * (not spawned from adacomp) and DEBUG is not defined.
  577.      */
  578. #ifdef EXIT_INTERNAL_ERROR
  579.     fprintf(stderr, "Unable to open file %s for %s \n", filename,
  580.       (strcmp(mode, "w") == 0 ? "writing"
  581.       : (strcmp(mode, "r") == 0 ? "reading"
  582.       : (strcmp(mode, "a") == 0 ? "appending"
  583.       :  mode))));
  584.     exit(RC_ABORT);
  585. #else
  586.     fprintf(stderr, "Unable to open file %s for %s \n", filename,
  587.       (strcmp(mode, "w") == 0 ? "writing"
  588.       : (strcmp(mode, "r") == 0 ? "reading"
  589.       : (strcmp(mode, "a") == 0 ? "appending"
  590.       :  mode))));
  591.     exit(RC_ABORT);
  592. #endif
  593. }
  594.  
  595. void ifclose(IFILE *ifile)                                    /*;ifclose*/
  596. {
  597.     FILE *file;
  598.  
  599.  
  600.     file = ifile->fh_file;
  601.     /* write out file header if write mode */
  602.     if (ifile->fh_mode == 'w') {
  603.         ifile->fh_mode = '\0';
  604.         ifseek(ifile, "update-header", 0L, 0);
  605.         fwrite((char *)ifile, sizeof(IFILE), 1, file);
  606.     }
  607.     if (file == (FILE *)0)
  608.         chaos("ifclose: closing unopened file");
  609.     fclose(file);
  610.     ifile->fh_file = (FILE *)0;
  611. }
  612.  
  613. void ifoclose(IFILE *ifile)                                    /*;ifoclose*/
  614. {
  615.     /* close file if still open */
  616.     if (ifile != (IFILE *) 0 && ifile->fh_file != (FILE *) 0) {
  617.         ifclose(ifile);
  618.     }
  619. }
  620.  
  621. long ifseek(IFILE *ifile, char *desc, long offset, int ptr)        /*;ifseek*/
  622. {
  623.     long begpos, endpos, seekval;
  624.     begpos = iftell(ifile);
  625.     seekval = fseek(ifile->fh_file, offset, ptr);
  626.     if (seekval == -1) chaos("ifseek: improper seek");
  627.  
  628.     endpos = iftell(ifile);
  629.     return endpos;
  630. }
  631.  
  632. long iftell(IFILE *ifile)                                    /*;iftell*/
  633. {
  634.     /* ftell, but arg is IFILE */
  635.     return ftell(ifile->fh_file);
  636. }
  637.  
  638. /* define MEAS_ALLOC to measure alloc performance */
  639. #define MEAS_ALLOC
  640. /* this causes each malloc action to write a line to standard output
  641.  * formatted as follows:
  642.  * code:one of a, r, f
  643.  * a    allocate block
  644.  * r    reallocate block
  645.  * f    free block
  646.  * the block address (integer)
  647.  * the block length (or zero if not applicable)
  648.  * the remainder of the line describes the action
  649.  */
  650.  
  651. #ifndef EXPORT
  652. char *emalloct(unsigned n, char *s)                                /*;emalloct*/
  653. {
  654.     char *p;
  655.     p = emalloc(n);
  656.     return p;
  657. }
  658. #endif
  659.  
  660. #ifndef EXPORT
  661. char *malloct(unsigned n, char *s)        /*;malloct*/
  662. {
  663.     /* like emalloct, but ok if not able to allocate block */
  664.     char *p;
  665.     p = malloc(n);
  666.     return p;
  667. }
  668. #endif
  669.  
  670. #ifndef EXPORT
  671. char *ecalloct(unsigned n, unsigned m, char *msg)
  672. {
  673.     char *p;
  674.     p = ecalloc(n, m);
  675.     return p;
  676. }
  677. #endif
  678.  
  679. #ifndef EXPORT
  680. char *erealloct(char *ptr, unsigned size, char *msg)        /*;erealloct*/
  681. {
  682.     char *p;
  683.     p = erealloc(ptr, size);
  684.     return p;
  685. }
  686. #endif
  687.  
  688. #ifndef EXPORT
  689. void efreet(char *p, char *msg)                                    /*;efreet*/
  690. {
  691.     efree(p);
  692. }
  693. #endif
  694.  
  695. char *predef_env()            /*;predef_env*/
  696. {
  697. #ifndef IBM_PC
  698.     char *s = getenv("ADAEDPREDEF");
  699.     if (s == (char *)0) s = get_libdir();
  700.     return s;
  701. #else
  702.     char *getenv();
  703.     return getenv("ADAED");
  704. #endif
  705. }
  706.  
  707. char *get_libdir()
  708. {
  709.     char *s = getenv("ADAED");
  710.     if (s == (char *)0) {
  711. #ifndef IBM_PC
  712.         return LIBDIR;
  713. #else
  714.         fprintf(stderr, "ADAED variable must be defined\n");
  715.         exitp(RC_ABORT);
  716. #endif
  717.     }
  718.     else
  719.         return s;
  720. }
  721.  
  722. char *parsefile(char *s, int *np, int *nb, int *ns)                /*;parsefile*/
  723. {
  724.     /* Parse file name s, returning the length of prefix, base part, and
  725.      * suffix in np, nb, and nl, respectively. A pointer to the start of
  726.      * the base part is returned, or the null pointer if no base part.
  727.      * The suffix is assumed to begin with period.
  728.      * The prefix ends with the last instance of any of the prefix characters.
  729.      */
  730.  
  731. #ifdef IBM_PC
  732.     char   *prefix_chars = ":/\\";
  733. #endif
  734. #ifdef BSD
  735.     char   *prefix_chars = "/";
  736. #endif
  737. #ifdef SYSTEM_V
  738.     char   *prefix_chars = "/";
  739. #endif
  740.     int    n,i;
  741.     char   *pb;
  742.     char   *p, *p2;
  743.     char   *suffix_chars = ".";
  744.     int    have_prefix = 0;
  745.  
  746.     n = strlen(s);
  747.     pb = s; /* assume name starts with base */
  748.     *ns = 0;
  749.     p = s + n; /* point to last (null) character in s */
  750.     /* find length of suffix */
  751.     /* but if find a prefix character first, then no suffix possible */
  752.     for (i = n - 1; i >= 0; i--) {
  753.         p--; 
  754.         for (p2 = prefix_chars; *p2 !='\0';) {
  755.             if (*p == *p2++) {
  756.                  /* (p-s) gives number of characters before suffix */
  757.                  have_prefix = 1;
  758.                  break;
  759.             }
  760.         }
  761.         if (!have_prefix) {
  762.             for (p2 = suffix_chars; *p2 !='\0';) {
  763.                 if (*p == *p2++) {
  764.                      /* (p-s) gives number of characters before suffix */
  765.                      *ns = n - (p - s);
  766.                      break;
  767.                 }
  768.             }
  769.         }
  770.     }
  771.     /* find length of prefix */
  772.     *np = 0;
  773.     p = s + n;
  774.     for (i = n - 1; i >= 0; i--) {
  775.         p--; 
  776.         for (p2 = prefix_chars; *p2 !='\0';) {
  777.             if (*p == *p2++) {
  778.                  p++; /* include last delimiter in prefix */
  779.                  /* (p-s) now gives prefix length*/
  780.                  *np = (p - s);
  781.                  pb = p;
  782.                  break;
  783.             }
  784.         }
  785.     }
  786.     /* base is what remains after removing prefix and suffix*/
  787.     *nb = n - (*np + *ns);
  788.     if (*nb == 0)
  789.         pb = (char *)0; /* if no base */
  790.     return pb;
  791. }
  792.